package com.yuyou.fn.settlement.service.impl;

import com.github.wens.framework.service.impl.SuperServiceImpl;
import com.github.wens.mybatisplus.examples.Example;
import com.github.wens.mybatisplus.toolkit.IdWorker;
import com.pingplusplus.Pingpp;
import com.pingplusplus.model.Charge;
import com.pingplusplus.model.Refund;
import com.yuyou.fn.common.constant.Constants;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.service.ISiteConfigService;
import com.yuyou.fn.common.util.BigDecimals;
import com.yuyou.fn.common.util.TimeUtils;
import com.yuyou.fn.settlement.entity.PayOrder;
import com.yuyou.fn.settlement.entity.RefundOrder;
import com.yuyou.fn.settlement.mapper.RefundOrderMapper;
import com.yuyou.fn.settlement.service.IPayOrderService;
import com.yuyou.fn.settlement.service.IRefundOrderService;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * RefundOrder 表数据服务层接口实现类
 *
 */
@Service
public class RefundOrderServiceImpl extends SuperServiceImpl<RefundOrderMapper, RefundOrder,Long> implements IRefundOrderService ,InitializingBean {
    private static final Logger log = LoggerFactory.getLogger(PayOrderServiceImpl.class) ;

    @Resource
    private ISiteConfigService siteConfigService ;


    private  String secretKey ;

    private String appId;

    private PublicKey pingxxPublicKey  ;

    @Resource
    private IPayOrderService payOrderService;


    @Value("${dev.env}")
    private boolean dev;

    @Override
    public void afterPropertiesSet() throws Exception {
        //dev = false ;
        secretKey = dev ? siteConfigService.getConfigValueFromCache("pingxx_test_secret_key") : siteConfigService.getConfigValueFromCache("pingxx_live_secret_key");
        appId = siteConfigService.getConfigValueFromCache("pingxx_app_id");
        String pubKeyString  = siteConfigService.getConfigValueFromCache("pingxx_public_key");
        pubKeyString = pubKeyString.replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", "");
        byte[] keyBytes = Base64.decodeBase64(pubKeyString);

        // generate public key
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        this.pingxxPublicKey = keyFactory.generatePublic(spec);

        Pingpp.apiKey = secretKey ;
    }

    @Override
    public Refund prepareRefund(Long refundOrderId,Long refundObjectId, Integer refundType, Long busId, Long payOrderId, BigDecimal amount, String description, String chargeId) {
/*        RefundOrder refundOrder=new RefundOrder();
        refundOrder.setRefundOrderId(IdWorker.getId());
        refundOrder.setStatus(Constants.REFUND_ORDER_STATUS_OF_NOT_PAY);
        refundOrder.setPayOrderId(payOrderId);
        refundOrder.setBusId(busId);
        refundOrder.setDescription(description);
        refundOrder.setCreateTime(TimeUtils.now());
        refundOrder.setUpdateTime(TimeUtils.now());
        refundOrder.setRefundType(refundType);
        refundOrder.setRefundObjectId(refundObjectId);
        refundOrder.setAmount(amount);
        this.insert(refundOrder);*/

        Map<String, Object> refundMap = new HashMap<String, Object>();
        refundMap.put("amount",  BigDecimals.formatBigDecimal(amount.multiply(new BigDecimal("100")),"0"));
        refundMap.put("description", description);
        Map<String, String> metadata=new HashMap<String, String>();
        metadata.put("refundObjectId", refundObjectId.toString());
        metadata.put("refundType",refundType.toString());
        metadata.put("refundOrderId",refundOrderId.toString());
        refundMap.put("metadata",metadata);
        Refund re = null;
        try{
            Charge ch = Charge.retrieve(chargeId);//ch_id 是已付款的订单号
            re=ch.getRefunds().create(refundMap);
            RefundOrder order=new RefundOrder();
            order.setRefundOrderId(refundOrderId);
            order.setRefundId(re.getId());
            this.updateSelectiveById(order);
            log.info("Create Refund result:{}" , re );
        }catch (Exception e){
            log.info("Create Refund result:{}" , re );
           // this.deleteById(refundOrder.getRefundOrderId());
            throw new BusException("Create refundOrder fail" ,e );
        }

        return re;
    }


    @Override
    @Transactional
    public Refund createRefundByPayOrderId(Long payOrderId, String description,Integer refundType) {
        PayOrder payOrder=payOrderService.findById(payOrderId);
        RefundOrder refundOrder=this.createRefundOrderByPayOrder(payOrder,description,refundType);
        Refund refund=this.prepareRefund(refundOrder.getRefundOrderId(),refundOrder.getRefundObjectId(),refundType,refundOrder.getBusId(),payOrderId,refundOrder.getAmount(),description,payOrder.getChargeId());
        return refund;
    }

    @Override
    public RefundOrder createRefundOrderByPayOrder(PayOrder payOrder, String description,Integer refundType) {
        RefundOrder refundOrder=new RefundOrder();
        refundOrder.setRefundOrderId(IdWorker.getId());
        refundOrder.setStatus(Constants.REFUND_ORDER_STATUS_OF_NOT_PAY);
        refundOrder.setPayOrderId(payOrder.getPayOrderId());
        refundOrder.setBusId(payOrder.getBusId());
        refundOrder.setDescription(description);
        refundOrder.setCreateTime(TimeUtils.now());
        refundOrder.setUpdateTime(TimeUtils.now());
        refundOrder.setRefundType(refundType);
        refundOrder.setRefundObjectId(payOrder.getBusId());
        refundOrder.setAmount(payOrder.getAmount());
        this.insert(refundOrder);
        return refundOrder;
    }

    @Override
    public RefundOrder findByRefundObjectId(Long refundObjectId) {
        Example<RefundOrder> refundOrderExample=RefundOrder.createExample();
        Example.Criteria criteria=refundOrderExample.createCriteria();
        criteria.andEqualTo("refundObjectId",refundObjectId);
        return this.findOneByExample(refundOrderExample);
    }

    @Override
    public RefundOrder findByRefundId(String refundId) {
        Example<RefundOrder> refundOrderExample=RefundOrder.createExample();
        Example.Criteria criteria=refundOrderExample.createCriteria();
        criteria.andEqualTo("refundId",refundId);
        return this.findOneByExample(refundOrderExample);
    }
}